package com.karaoke.oksrv.websocket

import com.fasterxml.jackson.databind.ObjectMapper
import com.google.gson.JsonParser
import com.karaoke.oksrv.NewsrvApplication
import com.karaoke.oksrv.UpdateInfo
import com.karaoke.oksrv.domain.DeviceData
import com.karaoke.oksrv.domain.Room
import com.karaoke.oksrv.domain.ScrollText
import com.karaoke.oksrv.domain.Song
import com.karaoke.oksrv.mapper.emedia.RoomMapper
import com.karaoke.oksrv.mapper.emedia.ScrollTextMapper
import com.karaoke.oksrv.mapper.master.FilePathMapper
import com.karaoke.oksrv.mapper.master.SongMapper
import com.karaoke.oksrv.mapper.master.SysParamMapper
import org.springframework.core.env.Environment
import reactor.bus.EventBus
import java.io.IOException
import java.util.*
import javax.websocket.*
import javax.websocket.server.PathParam
import javax.websocket.server.ServerEndpoint

/**
 * Created by allen on 2017/4/27.
 */
@ServerEndpoint(value = "/ws/room/{roomId}")
class RoomWebSocket
{
    private var session: Session? = null

    var room: Room? = null
    var roomId: String? = null

    @OnOpen
    fun onOpen(session: Session, @PathParam(value = "roomId") roomId: String)
    {
        this.session = session
        println("session open $roomId")
        this.roomId = roomId
        room = roomMapper.selectRoomInfo(roomId)
        webSocketMap.put(roomId, this)
        val paths = filePathMapper.selectAll()
        val dbVersion = sysParamMapper.selectByName("dbVersion").value
        val dev = DeviceData(room, paths, dbVersion)
        sendMessage(Message<DeviceData>(Command.RoomInit).apply { value = dev })
    }

    @OnClose
    fun onClose()
    {
        webSocketMap.remove(roomId)
    }

    @OnMessage
    fun onMessage(message: String, session: Session, @PathParam(value = "roomId") roomId: String)
    {
        val jsonObj = JsonParser().parse(message).asJsonObject
        val cmd = Command.valueOf(jsonObj.get("cmd").asString)
        when (cmd)
        {
            Command.SongPlayed    -> onSongPlayed(jsonObj.get("value").asString)
            Command.SongStartPlay -> onCurrentSongChanged(jsonObj.get("value").asString)
            Command.PublicSongs   -> getPublicSongs()
            Command.ScrollTexts   -> getScrollTexts()
            else                  ->
            {
            }
        }
    }

    private fun onSongPlayed(songId: String)
    {
        if (songId.isNotBlank())
        {
            val song = songMapper.selectByPrimaryKey(songId)
            song?.let {
                it.hot += 1
                if (it.isPublic.toInt() == 0)
                    songMapper.updateByPrimaryKey(song)
            }
        }
    }

    private fun onCurrentSongChanged(songId: String)
    {
        if (!songId.isNullOrBlank())
            room?.let {
                it.songNo = songId
                roomMapper.updateByPrimaryKeySelective(it)
            }
    }

    private fun getPublicSongs()
    {
        val songs = songMapper.selectPublicSongs()
        sendMessage(Message<List<Song>>(Command.PublicSongs).apply { value = songs })
    }

    private fun getScrollTexts()
    {
        val texts = scrollTextMapper.selectAll()
        sendMessage(Message<List<ScrollText>>(Command.ScrollTexts).apply { value = texts })
    }

    @OnError
    fun onError(session: Session, error: Throwable)
    {
        webSocketMap.remove(roomId)
    }

    @Throws(IOException::class)
    fun sendMessage(message: String)
    {
        this.session?.asyncRemote?.sendText(message)
    }

    fun sendMessage(msg: Message<*>)
    {
        this.session?.basicRemote?.sendText(mapper.writeValueAsString(msg))
    }

    val mapper: ObjectMapper by lazy {
        NewsrvApplication.getBean("customObjectMapper") as ObjectMapper
    }


    val eventbus: EventBus by lazy {
        NewsrvApplication.getBean(EventBus::class.java)
    }

    val roomMapper: RoomMapper by lazy {
        NewsrvApplication.getBean(RoomMapper::class.java)
    }

    val songMapper: SongMapper by lazy {
        NewsrvApplication.getBean(SongMapper::class.java)
    }

    val scrollTextMapper: ScrollTextMapper by lazy {
        NewsrvApplication.getBean(ScrollTextMapper::class.java)
    }

    val filePathMapper: FilePathMapper by lazy {
        NewsrvApplication.getBean(FilePathMapper::class.java)
    }

    val sysParamMapper: SysParamMapper by lazy {
        NewsrvApplication.getBean(SysParamMapper::class.java)
    }

    val webSocketMap: WeakHashMap<String, RoomWebSocket> by lazy {
        NewsrvApplication.getBean("webSocketMap") as WeakHashMap<String, RoomWebSocket>
    }

    val updateInfo by lazy {
        NewsrvApplication.getBean(UpdateInfo::class.java)
    }
}